#include <stdlib.h>
#include <stdio.h>

#include "SignalGeneration.hpp"

#include <time.h>

extern "C"
{
#include "AlgorithmSetup.h"
#include "CleanAlgorithm.h"
#include "ProcessPriority.h"
#include "TimeMeasurement.h"
}

#include <iostream>
#include <iomanip>
#include <algorithm>

#include <string.h>

using namespace std;


#ifdef DEBUG
#define NUM_TEST_RUNS 1
#else
#define NUM_TEST_RUNS 1
#endif

int main(int argc, char **argv)
{
	// Generate a time vector according to the radar's burst settings
	//CSamplingGenerationInfo SamplingGenerationInfo(1.0/32.0, 32);
	CSamplingGenerationInfo SamplingGenerationInfo(0.5, 8);
	//SamplingGenerationInfo.AddBurst(1.0, 1.0 / 32);
	SamplingGenerationInfo.AddBurst(19.0, 1.5);
	SamplingGenerationInfo.AddBurst(22.0, 1.5);
	SamplingGenerationInfo.AddBurst(25.0, 0);
	CSamplingInfo SamplingInfo = SamplingGenerationInfo.GenerateSampling();

	// Generate a random "analog" signal with some oscillators and noise
	double TotalObservationTime = SamplingInfo.TotalObservationTime();
	CSignalGenerationInfo SignalGenerationInfo(TotalObservationTime, 10000);
	//SignalGenerationInfo.AddOscillator(1.0, 1.0);
	//SignalGenerationInfo.AddOscillator(2.0, 2.0);
	SignalGenerationInfo.AddOscillator(1.88, 5.0);
	SignalGenerationInfo.AddOscillator(-1.25, 4.0);
	//SignalGenerationInfo.AddOscillator(0.576, 2.8);
	//SignalGenerationInfo.AddOscillator(0.0, 0.0);
	//SignalGenerationInfo.NoiseAmplitude(0.3);
	SignalGenerationInfo.Phase(atan(1.0) * 4.0);
	CSignal Signal = SignalGenerationInfo.GenerateSignal();

	// Spectrum configuration
	//double MaxDetectFrequency = 16.0;
	//int SpectrumSize = 32;
	double MaxDetectFrequency = 3.0;
	int SpectrumSize = 4238;
	

	
	// Use the sampling info to get the samples from our generated signal that the radar would produce
	int SampleCount = SamplingInfo.TotalSampleCount();
	double *SamplesRe = new double[SampleCount]; // Real part of the algorithm's actual input
	double *SamplesIm = new double[SampleCount]; // Imag part of the algorithm's actual input
	Signal.GetSignalSamples(SamplesRe, SamplesIm, SamplingInfo);

	//
	// algorithm setup
	//
	
	int TimeVectorSize = SamplingInfo.TimeVector().size();
	double *TimeVector = new double[TimeVectorSize];
	for (int i = 0; i < TimeVectorSize; i++)
	{
		TimeVector[i] = SamplingInfo.TimeVector(i);
	}
	
	int WindowSize = GetFourierWindowSize(SpectrumSize);
	
	double *WindowRe = new double[WindowSize];
	double *WindowIm = new double[WindowSize];
	
	GenerateFourierWindow(MaxDetectFrequency, SpectrumSize, SampleCount, TimeVector, WindowRe, WindowIm);

	int SinCosArraySize = GetSinCosArraySize(SampleCount, SpectrumSize);
	
	double *SinArray = new double[SinCosArraySize];
	double *CosArray = new double[SinCosArraySize];
	
	GenerateSinCosArray(SampleCount, TimeVector, MaxDetectFrequency, SpectrumSize, SinArray, CosArray);

#ifdef WIN32
#define ARRAY_TXT "array_windows.txt"
#else
#define ARRAY_TXT "array.txt"
#endif
	FILE *samples = fopen(ARRAY_TXT, "w");
	for (int i = 0; i < SinCosArraySize; i++)
	{
		fprintf(samples, "%lf, %lf\n", SinArray[i], CosArray[i]);
	}
	fclose(samples);
	
	int NumResults = SignalGenerationInfo.OscillatorCount();
	
	// highest priority class for this process
	SetHighPriority();
	
	
	

	//
	// Output of current configuration
	//

	cout << "Sampling configuration" << endl;
	cout << setw(8) << "Burst" << setw(16) << "DeltaT" << setw(16) << "SamplingFreq" << setw(16) << "NyquistFreq" << endl;
	for (int i = 0; i < SamplingGenerationInfo.NumberOfBursts(); i++)
	{
		cout << setw(8) << i << setw(16) << SamplingInfo.GetDeltaT(i) << setw(16) << SamplingInfo.GetSampleFrequency(i) << setw(16) << SamplingInfo.GetSampleFrequency(i) / 2.0 << endl;
	}
	cout << endl;

	cout << "Signal generator configuration" << endl;
	cout << "Noise amplitude: " << SignalGenerationInfo.NoiseAmplitude() << endl;
	cout << "Phase: " << SignalGenerationInfo.Phase() << endl;
	cout << setw(16) << "Oscillator Freq" << setw(16) << "Amplitude" << endl;
	for (int i = 0; i < SignalGenerationInfo.OscillatorCount(); i++)
	{
		cout << setw(16) << SignalGenerationInfo.GetFrequency(i) << setw(16) << SignalGenerationInfo.GetAmplitude(i) << endl;
	}
	cout << endl;

	double DeltaF = MaxDetectFrequency / SpectrumSize * 2.0;

	cout << "Spectrum configuration" << endl;
	cout << "MaxDetectFrequency: " << MaxDetectFrequency << endl;
	cout << "SpectrumSize: " << SpectrumSize << endl;
	cout << "DeltaF: " << DeltaF << endl;
	cout << "Window size: " << WindowSize << endl;
	cout << "SinCos Array size: " << SinCosArraySize << endl;
	cout << endl;




	
	
	
	
	//
	// plain c algorithm
	//
	
	{
		cout << "C algorithm starting" << endl;
		
		double *SpectrumRe = new double[SpectrumSize];
		double *SpectrumIm = new double[SpectrumSize];
		double *SpectrumAbs = new double[SpectrumSize];
		
		double *ResultAmplitudes = new double[NumResults];
		int *ResultFrequencies = new int[NumResults];
		
		void *TimeStart = StartTimeMeasurement();

		for (int i = 0; i < NUM_TEST_RUNS; i++)
		{
			Analyze(SpectrumSize, SampleCount, CosArray, SinArray, SpectrumRe, SpectrumIm, SpectrumAbs, SamplesRe, SamplesIm, NumResults, ResultFrequencies, ResultAmplitudes, WindowRe, WindowIm);
		}
		
		double Time = EndTimeMeasurement(TimeStart, NUM_TEST_RUNS);
		
		cout << "CPU time: " << Time << " us" << endl;
		
		cout << setw(16) << "Frequency" << setw(16) << "Amplitude" << endl;
		for (int i = 0; i < NumResults; i++)
		{
			cout << setw(16) << GetResultFrequency(SpectrumSize, MaxDetectFrequency, ResultFrequencies[i]) << setw(16) << ResultAmplitudes[i] << endl;
		}
		
		cout << endl;
	}

	return 0;
}

